
static unsigned int irq_err_count = 0;
static struct irq_desc irq_desc[CONFIG_NR_IRQS];

static inline void mask_irq(struct irq_desc *desc)
{   
    if (desc->chip->irq_mask) {
        desc->chip->irq_mask();
        desc->state |= IRQS_MASKED;
    }   
}

static inline void unmask_irq(struct irq_desc *desc)
{
    if (desc->chip->irq_unmask) {
        desc->chip->irq_unmask(desc);
		desc->state &= ~IRQS_MASKED;
    }
}   

static inline void mask_ack_irq(struct irq_desc *desc)
{
    if (desc->chip->irq_mask_ack) {
        desc->chip->irq_mask_ack(desc);
		desc->state |= IRQS_MASKED;
    } else {
		if (desc->chip_irq_mask) {
			desc->chip->irq_mask(desc);
			desc->state |= IRQS_MASKED;
		}
        if (desc->chip->irq_ack)
            desc->chip->irq_ack(desc);
    }
}

static inline void ack_bad_irq(unsigned int irq)
{
	irq_err_count++;
}

static void ack_bad(struct irq_desc *desc)
{
    ack_bad_irq(desc->irq);
}   

static struct irq_chip irq_no_chip = {
	.name			= "none",
	.irq_ack		= ack_bad,
};

int irq_set_chip(unsigned int irq, struct irq_chip *chip)
{
	struct irq_desc *desc;
	unsigned int flags;

	if (irq >= CONFIG_NR_IRQS) 
		return -EINVAL;

	desc = &irq_desc[irq];

	if (!chip)
		chip = &irq_no_chip;

	local_irq_save(flags);
	desc->chip = chip;
	local_irq_restore(flags);

	return 0;
}

static void handle_bad_irq(unsigned int irq, struct irq_desc *desc)
{
    ack_bad_irq(irq);
}

int irq_set_handler(unsigned int irq, irq_flow_handler_t handle, unsigned int is_chained)
{
    unsigned int flags;
    struct irq_desc *desc;

	if (irq >= CONFIG_NR_IRQS) 
		return -EINVAL;

	desc = &irq_desc[irq];

	if (!handle) 
		handle = handle_bad_irq;

	local_irq_save(flags);
    desc->handle_irq = handle;

    if (is_chained || handle == handle_bad_irq) 
		desc->flags |= IRQF_NOREQUEST;
	local_irq_restore(flags);

	return 0;
}

int irq_set_flags(unsigned int irq, unsigned int flags)
{       
	unsigned int _flags;
    struct irq_desc *desc;

	if (irq >= CONFIG_NR_IRQS) 
		return -EINVAL;

	desc = &irq_desc[irq];
	
	local_irq_save(_flags);
	desc->flags = flags;
	local_irq_restore(_flags);

	return 0;
}  

int irq_set_type(unsigned int irq, unsigned int type)
{
	struct irq_desc *desc;
	struct irq_chip *chip;
	unsigned int flags, ret;
	unsigned int unmask = 0;

	if (irq >= CONFIG_NR_IRQS) 
		return -EINVAL;

	desc = &irq_desc[irq];	
	chip = desc->chip;
	if (!chip->irq_set_type) 
		return -ENODEV;

	type &= IRQ_TYPE_SENSE_MASK;
	if (type == IRQ_TYPE_NONE) 
		return -EINVAL;

	if (desc->flags & IRQF_SET_TYPE_MASKED) {
		if (!(desc->state & IRQS_MASKED)) {
			mask_irq(desc);
			unmask = 1;
		}
	}

	ret = chip->irq_set_type(desc, flags);

	if (!IS_ERR(ret)) {
		desc->state &= ~IRQS_SENSE_MASK;		
		desc->state |= type;
	}

	if (unmask)
		unmask_irq(desc);

	return ret;
}

int __exception generic_handle_irq(unsigned int irq)
{
    struct irq_desc *desc;

	if (irq >= CONFIG_NR_IRQS) 
		return -EINVAL;

	desc = &irq_desc[irq];

	desc->handle_irq(irq, desc);
    return 0;
}  

void __exception do_irq(unsigned int irq)
{
	if (irq >= CONFIG_NR_IRQS) 
		ack_bad_irq(irq);
	else 
		generic_handle_irq(irq);
}

static int __exception handle_irq_event(struct irq_desc *desc)
{   
    struct irqaction *action = desc->action;
	unsigned int irq = desc->irq;
    int ret;

	desc->state &= ~IRQS_PENDING;
	desc->state |= IRQS_INPROGRESS;
	if (!(desc->flags & IRQF_DISABLE)) 
		local_irq_enable();
	do {
		ret = action->handler(irq, action->priv);
		action = action->next;
	} while (action);
	local_irq_disable();
	desc->state &= ~IRQS_INPROGRESS;

    return ret;
}

/**
 *  handle_level_irq - Level type irq handler
 *  @irq:   the interrupt number
 *  @desc:  the interrupt description structure for this irq
 *
 *  Level type interrupts are active as long as the hardware line has
 *  the active level. This may require to mask the interrupt and unmask
 *  it after the associated handler has acknowledged the device, so the
 *  interrupt line is back to inactive.
 */
void __exception handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
    mask_ack_irq(desc);

    if (!desc->action)
		return;

    handle_irq_event(desc);

	unmask_irq(desc);
}

/**
 *  handle_edge_irq - edge type IRQ handler
 *  @irq:   the interrupt number
 *  @desc:  the interrupt description structure for this irq
 *
 *  Interrupt occures on the falling and/or rising edge of a hardware
 *  signal. The occurrence is latched into the irq controller hardware
 *  and must be acked in order to be reenabled. After the ack another
 *  interrupt can happen on the same source even before the first one
 *  is handled by the associated event handler. If this happens it
 *  might be necessary to disable (mask) the interrupt depending on the
 *  controller hardware. This requires to reenable the interrupt inside
 *  of the loop which handles the interrupts which have arrived while
 *  the handler was running. If all pending interrupts are handled, the
 *  loop is left.
 */
void __exception handle_edge_irq(unsigned int irq, struct irq_desc *desc)
{
    /*
     * If we're currently running this IRQ, 
     * we shouldn't process the IRQ. Mark it pending, handle
     * the necessary masking and go out
     */
    if (desc->state & IRQS_INPROGRESS) {
		desc->state |= IRQS_PENDING;
		mask_ack_irq(desc);
		return;
    }

	if (!desc->action) {
		mask_ack_irq(desc);
		return;
	}

    /* Start handling the irq */
    desc->chip->irq_ack(desc);

    do {
        if (desc->state & IRQS_PENDING) {
            if (desc->state & IRQS_MASKED)
                unmask_irq(desc);
        }

        handle_irq_event(desc);

    } while (desc->state & IRQS_PENDING);
}

/**
 *  handle_simple_irq - Simple and software-decoded IRQs.
 *  @irq:   the interrupt number
 *  @desc:  the interrupt description structure for this irq
 *
 *  Simple interrupts are either sent from a demultiplexing interrupt
 *  handler or come from hardware, where no interrupt hardware control
 *  is necessary.
 *  
 *  Note: The caller is expected to handle the ack, clear, mask and
 *  unmask issues if necessary.
 */ 
void __exception handle_simple_irq(unsigned int irq, struct irq_desc *desc)
{   
	if (desc->state & IRQS_INPROGRESS) 
		return;
		
    if (!desc->action)
		return;

    handle_irq_event(desc);
}

int request_irq(unsigned int irq, irq_handler_t handler, unsigned int flags, void *priv, struct irqaction *action)
{
	struct irq_desc *desc;

	if (irq >= CONFIG_NR_IRQS) 
		return -EINVAL;

	desc = &irq_desc[irq];	
	if (desc->state & IRQF_NOREQUEST) 
		return -EINVAL;

	if (!handler)
		return -EINVAL;

	action->handler = handler;
	desc->flags |= flags;
	action->priv = priv;	
	return 0;	
}

